﻿using System;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Threading;

namespace AutoUpdater
{
    /// <summary>
    ///   文件更新器窗体
    /// </summary>
    internal partial class FrmUpdater : Form
    {
        #region 构造函数

        /// <summary>
        ///   构造函数
        /// </summary>
        /// <param name = "updater">数据更新器</param>
        public FrmUpdater(Updater updater)
        {
            this.updater = updater;

            if (!string.IsNullOrEmpty(updater.WindowText))
            {
                Text = updater.WindowText;
            }

            if (updater.WindowIcon != null)
            {
                Icon = updater.WindowIcon;
            }

            InitializeComponent();
        }

        #endregion 构造函数

        #region 字段属性

        /// <summary>
        ///   数据更新器
        /// </summary>
        private readonly Updater updater;

        /// <summary>
        ///   当前正在下载的文件
        /// </summary>
        internal string CurrentFile = string.Empty;

        /// <summary>
        ///   当前异常信息
        /// </summary>
        internal Exception Exception;

        /// <summary>
        ///   下载线程
        /// </summary>
        private Thread threadDownload;

        /// <summary>
        ///   更新下载进度条代理
        /// </summary>
        /// <param name = "value">当前值</param>
        /// <param name = "max">最大值</param>
        /// <param name = "desc">描述</param>
        private delegate void UpdateProgressHandler(int value, int max, string desc);

        #endregion 字段属性

        #region 窗体事件

        private void FrmUpdate_Load(object sender, EventArgs e)
        {
            pgbTotalProgress.Maximum = updater.FileList.Count;
            pgbTotalProgress.Value = 0;
            threadDownload = new Thread(Download);
            threadDownload.Start();
        }

        private void FrmUpdater_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (threadDownload.IsAlive)
            {
                threadDownload.Abort();
            }
        }

        private void btnConfirm_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.OK;
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            DialogResult = DialogResult.Cancel;
        }

        #endregion 窗体事件

        #region 私有方法

        /// <summary>
        ///   下载文件
        /// </summary>
        private void Download()
        {
            try
            {
                var downloadNum = 0;

                //委托实例
                UpdateProgressHandler currentProgress = UpdateCurrentProgress;
                UpdateProgressHandler totalProgress = UpdateTotalProgress;

                foreach (var file in updater.FileList)
                {
                    #region 下载单个文件

                    CurrentFile = file;
                    var url = updater.RemoteUrl + file;
                    var savePath = updater.SavePath + file;

                    /*
                     * 使用 WebRequest.Create 方法初始化新的 HttpWebRequest 对象。如果统一资源标识符 (URI) 的方案是 http:// 或 https://，则 Create 返回 HttpWebRequest 对象 
                     * 如果 URI 方案是 file://，则 Create 方法返回 FileWebRequest 对象。
                     * 如果 URI 方案是 ftp://，则 Create 方法返回 FtpWebRequest 对象。
                     */
                    var webRequest = WebRequest.Create(url);
                    //如果用户名不为空则设置身份登录信息
                    if (!string.IsNullOrEmpty(updater.Uid))
                    {
                        var ce = new NetworkCredential(updater.Uid, updater.Pwd);
                        if (!string.IsNullOrEmpty(updater.Domain))
                        {
                            ce.Domain = updater.Domain;
                        }
                        webRequest.Credentials = ce;
                    }
                    using (var webResponse = webRequest.GetResponse())
                    using (var binaryReader = new BinaryReader(webResponse.GetResponseStream()))
                    using (var fs = new FileStream(savePath, FileMode.Create))
                    {
                        var numBytesRead = 0;
                        var numTotalBytes = (int) webResponse.ContentLength;
                        var numCurrentKBytes = 0;
                        var numTotalKBytes = numTotalBytes/1024;

                        //循环读取文件.....
                        var len = numTotalBytes;
                        while (true)
                        {
                            var buffer = binaryReader.ReadBytes(updater.BufferSize);
                            fs.Write(buffer, 0, buffer.Length);
                            fs.Flush();
                            numBytesRead += buffer.Length;
                            len -= buffer.Length;
                            numCurrentKBytes = numBytesRead/1024;

                            //更新当前进度
                            var str = "正在下载：" + file + "(" + numCurrentKBytes + "/" + numTotalKBytes + "KB)";
                            Invoke(currentProgress, numBytesRead, numTotalBytes, str);

                            //一个文件下载完成
                            if (len <= 0)
                            {
                                break;
                            }
                        }

                        //关闭资源
                        fs.Close();
                        binaryReader.Close();
                        webResponse.Close();

                        //更新总体进度
                        downloadNum++;
                        Invoke(totalProgress, downloadNum, updater.FileList.Count, "");
                    }

                    #endregion 下载单个文件
                }

                //更新总进度
                Invoke(totalProgress, downloadNum, updater.FileList.Count, "下载完成，请点击确定执行相关操作。");

                //更新确定按钮状态
                EventHandler eh = delegate { btnConfirm.Enabled = true; };
                Invoke(eh);
            }
            catch (ThreadAbortException)
            {
                //TODO 过滤掉终止线程异常
            }
            catch (Exception ex)
            {
                Exception = ex;
                DialogResult = DialogResult.No;
            }
        }

        /// <summary>
        ///   更新当前进度
        /// </summary>
        /// <param name = "value">当前值</param>
        /// <param name = "max">最大值</param>
        /// <param name = "desc">描述</param>
        private void UpdateCurrentProgress(int value, int max, string desc)
        {
            pgbCurrentProgress.Maximum = max;
            pgbCurrentProgress.Value = value;
            lbProgress.Text = desc;
        }

        /// <summary>
        ///   更新总进度
        /// </summary>
        /// <param name = "value">当前值</param>
        /// <param name = "max">最大值</param>
        /// <param name = "desc">描述</param>
        private void UpdateTotalProgress(int value, int max, string desc)
        {
            pgbTotalProgress.Maximum = max;
            pgbTotalProgress.Value = value;

            if (!string.IsNullOrEmpty(desc))
            {
                lbProgress.Text = desc;
            }
        }

        #endregion 私有方法
    }
}